<template>
  <section class="comp-actions">
    <div class="layer-entrance"
      :class="[roomData.rotate && ('rotate-' + roomData.rotate)]"
      v-show="!isRunAwayShow"
    >
      <div class="top-enter"
        v-if="roomData.doors && roomData.doors.includes(0)"
        @click="enter(0)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M13 12V20H11V12H4L12 4L20 12H13Z"></path></svg>
      </div>
      <div class="right-enter"
        v-if="roomData.doors && roomData.doors.includes(1)"
        @click="enter(1)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M12 13H4V11H12V4L20 12L12 20V13Z"></path></svg>
      </div>
      <div class="bottom-enter"
        v-if="roomData.doors && roomData.doors.includes(2)"
        @click="enter(2)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M13 12H20L12 20L4 12H11V4H13V12Z"></path></svg>
      </div>
      <div class="left-enter"
        v-if="roomData.doors && roomData.doors.includes(3)"
        @click="enter(3)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M12 13V20L4 12L12 4V11H20V13H12Z"></path></svg>
      </div>
    </div>
    <div class="layer-rotate"
      v-show="isRotateNewRoomShow">
      <div class="new-room"
        :class="[rotateDeg && ('rotate-' + rotateDeg), 'room-' + newRoom.image]"></div>
      <div class="icon-button icon-rotate"
        @click="rotate()">
        <img class="icon" src="@/assets/icon_rotate.svg" alt="">
      </div>
      <div class="icon-button icon-confirm"
        @click="confirmRotate()">
        <img class="icon" src="@/assets/icon_confirm.svg" alt="">
      </div>
    </div>
    <div class="layer-runaway"
      v-show="isRunAwayShow">
      <div class="top-enter"
        v-if="runAwayRooms.up"
        @click="dealRunAway(0, -1)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M13 12V20H11V12H4L12 4L20 12H13Z"></path></svg>
      </div>
      <div class="right-enter"
        v-if="runAwayRooms.right"
        @click="dealRunAway(1, 0)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M12 13H4V11H12V4L20 12L12 20V13Z"></path></svg>
      </div>
      <div class="bottom-enter"
        v-if="runAwayRooms.down"
        @click="dealRunAway(0, 1)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M13 12H20L12 20L4 12H11V4H13V12Z"></path></svg>
      </div>
      <div class="left-enter"
        v-if="runAwayRooms.left"
        @click="dealRunAway(-1, 0)">
        <svg class="icon-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="240" height="240" fill="currentColor"><path d="M12 13V20L4 12L12 4V11H20V13H12Z"></path></svg>
      </div>
    </div>
  </section>
</template>

<script>
import eventBus from '@/EventBus'
import system from '@/models/system'
import player from '@/models/Player'
import ItemConfig from '@/models/config/Item'
import RoomConfig from '@/models/config/Room'
import SystemConfig from '@/models/config/System'
import { getHeadToLocation, shuffle } from '@/utils/CommonUtil'
import { getVisitedRooms, hasValidEntrance, getBreakInEntrance, checkWinGame } from '@/ctrls/CommonCtrl'

export default {
  props: {
    roomData: {
      type: Object,
      required: true
    }
  },

  data () {
    return {
      isRotateNewRoomShow: false,
      rotateDeg: 0,
      newRoom: {
        image: ''
      },
      isRunAwayShow: false,
      runAwayRooms: {},
      newLocation: {},
      where: '',
      phase: ''
    }
  },

  mounted () {
    eventBus.$on('notifyMessageAction', ({ action, tag, index }) => {
      if (tag && tag.source === 'getItem') {
        if (action === 'confirm') {
          // deal fetch item
          tag.postEvent ? this.phase = 'specialItem' : this.phase = 'item'
        } else {
          // cancel fetch item
          if (tag.postEvent) {
            this.phase = ''
            if (!hasValidEntrance()) {
              this.dealBreakIn()
            }
          } else {
            this.phase = 'specialEvent'
          }
        }
        this.dealRoomStory()
      } else if (tag && tag.source === 'getSpecialItem') {
        if (action === 'confirm') {
          // deal fetch item
          this.phase = 'specialItem'
          this.dealRoomStory()
        } else {
          // cancel fetch item
          this.phase = ''
          if (!hasValidEntrance()) {
            this.dealBreakIn()
          }
        }
      } else if (tag && tag.source === 'dropEventItem') {
        if (index >= player.items.length) {
          // drop the new item, do nothing
        } else {
          // drop exist item, replace it with new item
          player.items.splice(index, 1, tag.newItem)
        }
        this.phase = 'specialEvent'
        this.dealRoomStory()
      } else if (tag && tag.source === 'dropSpecialItem') {
        if (index >= player.items.length) {
          // drop the new item, do nothing
        } else {
          // drop exist item, replace it with new item
          player.items.splice(index, 1, tag.newItem)
        }
        this.phase = ''
        if (!hasValidEntrance()) {
          this.dealBreakIn()
        }
      } else if (tag && tag.source === 'getTotem') {
        if (action === 'confirm') {
          this.phase = 'totem'
          this.dealRoomStory()
        } else {
          // cancel get totem
          this.phase = ''
          if (!hasValidEntrance()) {
            this.dealBreakIn()
          }
        }
      } else if (tag && tag.source === 'finishGame') {
        this.phase = 'finishGame'
        this.dealRoomStory()
      } else if (tag && tag.source === 'restart') {
        this.isRotateNewRoomShow = false
        this.rotateDeg = 0
        this.newRoom = {
          image: ''
        }
        this.isRunAwayShow = false
        this.runAwayRooms = {}
        this.newLocation = {}
        this.where = ''
        this.phase = ''
      }
    })
    eventBus.$on('notifyBattleResult', ({ result, tag }) => {
      if (result === 'runAway') {
        // 1. check visited rooms 2. show message 3. end
        const visitedRooms = getVisitedRooms()
        if (visitedRooms.count === 1) {
          // only 1 valid visited room, get back into it
          if (visitedRooms.up) {
            this.dealRunAway(0, -1)
          } else if (visitedRooms.down) {
            this.dealRunAway(0, 1)
          } else if (visitedRooms.left) {
            this.dealRunAway(-1, 0)
          } else if (visitedRooms.right) {
            this.dealRunAway(1, 0)
          }
        } else {
          // choose which visited room to run away into
          this.runAwayRooms = visitedRooms
          this.isRunAwayShow = true
        }
      } else if (result === 'win') {
        if (tag && tag.source === 'finishGame') {
          if (checkWinGame()) {
            eventBus.$emit('notifyMessage', {
              message: '你成功地结束了一切噩梦，游戏胜利🎉',
              confirmBtnText: '重新开始',
              tag: {
                source: 'restart'
              }
            })
          }
        } else if (tag && tag.source === 'breakIn') {
          // NOTE after break in, no more events
          this.phase = ''
        } else if (tag && tag.postEvent) {
          this.phase = ''
          if (!hasValidEntrance()) {
            this.dealBreakIn()
          }
        } else {
          this.phase = 'specialEvent'
          this.dealRoomStory()
        }
      }
    })
  },

  beforeDestroy () {
    eventBus.$off('notifyMessageAction')
    eventBus.$off('notifyBattleResult')
  },

  methods: {
    enter (doorIndex) {
      // console.log('enter door ', doorIndex)
      const headToLocation = getHeadToLocation(this.roomData, doorIndex)
      if (system.map.find(r => r.x === headToLocation.x && r.y === headToLocation.y)) {
        // visited room
        player.x = headToLocation.x
        player.y = headToLocation.y
        eventBus.$emit('notifyRedraw')
        this.phase = 'roomEvent'
        this.dealRoomStory()
      } else {
        // unknown room
        if (this.roomData.outDoor && this.roomData.outDoor.length && this.roomData.outDoor.includes(doorIndex)) {
          // go outside
          const toShuffleOutdoors = []
          let patio = null
          RoomConfig.outdoors.forEach(r => {
            if (r.key === 'patio') {
              patio = {
                ...r,
                where: 'outdoor'
              }
            } else {
              toShuffleOutdoors.push({
                ...r,
                where: 'outdoor'
              })
            }
          })
          system.outdoors = shuffle(toShuffleOutdoors)
          // console.log(system)
          this.dealNewRoom(patio, headToLocation)
        } else {
          // go to a new room
          // console.log(this.roomData, system)
          let newRoom = null
          if (this.roomData.where === 'indoor' && system.indoors.length) {
            newRoom = system.indoors.pop()
          } else if (this.roomData.where === 'outdoor' && system.outdoors.length) {
            newRoom = system.outdoors.pop()
          } else {
            // no more rooms
            eventBus.$emit('notifyMessage', {
              message: '这个方向似乎被堵死了...'
            })
            return
          }
          if (newRoom) {
            this.dealNewRoom(newRoom, headToLocation)
          }
        }
      }
    },
    dealNewRoom (room, location) {
      this.newRoom = room
      this.rotateDeg = 0
      this.newLocation = location
      this.where = this.roomData.where
      this.isRotateNewRoomShow = true
      player.x = location.x
      player.y = location.y
      eventBus.$emit('notifyRedraw')
    },
    rotate () {
      if (this.rotateDeg === 270) {
        this.rotateDeg = 0
      } else {
        this.rotateDeg += 90
      }
    },
    confirmRotate () {
      system.map.push({
        ...this.newRoom,
        x: this.newLocation.x,
        y: this.newLocation.y,
        rotate: this.rotateDeg,
        where: this.newRoom.where || this.where
      })
      this.isRotateNewRoomShow = false
      eventBus.$emit('notifyRedraw')
      this.phase = 'roomEvent'
      this.dealRoomStory()
    },
    dealRoomStory () {
      // 1. room event
      // 1.1 battle
      // 1.1.1 battle result
      // 1.1.2 run away
      // 1.2 effect
      // 1.3 fetch item
      // 1.3.1 drop item
      // 2. special event
      // 2.1 effect
      // 2.2 fetch special item
      // 2.2.1 drop item
      switch (this.phase) {
        case 'roomEvent':
          this.dealEvent()
          break
        case 'item':
          this.dealItem()
          break
        case 'specialEvent':
          this.dealSpecialEvent()
          break
        case 'specialItem':
          this.dealItem(true)
          break
        case 'totem':
          this.dealFetchTotem()
          break
        case 'finishGame':
          this.dealFinishGame()
          break
        default:
      }
    },
    dealEvent (postEvent = false) {
      if (!system.events.length) {
        // no more events, should shuffle
        eventBus.$emit('notifyShuffleEvents')
      }
      if (!system.events.length) {
        // when game over, no more events after shuffling
        return
      }
      // NOTE there's a possible bug, deal event before shuffling finish, should confirm
      console.log('before deal event', JSON.stringify(system))
      const event = system.events.pop()
      const toDealEvent = event.timeEvents[system.time]
      switch (toDealEvent.key) {
        case 'msg':
          eventBus.$emit('notifyMessage', {
            message: toDealEvent.desc
          })
          if (!postEvent) {
            this.phase = 'specialEvent'
            this.dealRoomStory()
          }
          break
        case 'getItem':
          eventBus.$emit('notifyMessage', {
            message: '角落有件物品，要花点时间去看看吗？',
            confirmBtnText: '查看物品',
            cancelBtnText: '忽略',
            tag: {
              source: 'getItem',
              postEvent
            }
          })
          break
        case 'battle':
          eventBus.$emit('notifyHappenBattle', {
            count: toDealEvent.zombies,
            tag: {
              postEvent
            }
          })
          break
        case 'effect':
          player.hp += toDealEvent.addHp
          eventBus.$emit('notifyMessage', {
            message: `${toDealEvent.desc}（生命${toDealEvent.addHp >= 0 ? '+' : ''}${toDealEvent.addHp}）`
          })
          if (!postEvent) {
            this.phase = 'specialEvent'
            this.dealRoomStory()
          }
          break
      }
    },
    dealSpecialEvent () {
      // NOTE special event is based on the room
      const stayedRoom = system.map.find(r => r.x === player.x && r.y === player.y)
      if (stayedRoom.addHp > 0) {
        player.hp += stayedRoom.addHp
        eventBus.$emit('notifyMessage', {
          message: `生命+${stayedRoom.addHp}`
        })
      } else if (stayedRoom.key === 'storage') {
        // can fetch item
        eventBus.$emit('notifyMessage', {
          message: '角落有件物品，要花点时间去看看吗？',
          confirmBtnText: '查看物品',
          cancelBtnText: '忽略',
          tag: {
            source: 'getSpecialItem'
          }
        })
      } else if (stayedRoom.key === 'evilTemple' && !player.gotTotem) {
        // can fetch totem
        eventBus.$emit('notifyMessage', {
          message: '你感到隐隐传来的邪恶感觉，要现在搜索邪恶图腾吗？',
          confirmBtnText: '立刻搜索',
          cancelBtnText: '下次再说',
          tag: {
            source: 'getTotem'
          }
        })
      } else if (stayedRoom.key === 'graveyard' && player.gotTotem) {
        // can bury totem in grave
        eventBus.$emit('notifyMessage', {
          message: '将邪恶图腾填埋到这里！结束一切混乱',
          confirmBtnText: '填埋',
          tag: {
            source: 'finishGame'
          }
        })
      } else {
        // no special event
        this.phase = ''
        if (!hasValidEntrance()) {
          this.dealBreakIn()
        }
      }
    },
    dealFinalEvent () {
      if (!system.events.length) {
        // no more events, should shuffle
        eventBus.$emit('notifyShuffleEvents')
      }
      if (!system.events.length) {
        // when game over, no more events after shuffling
        return
      }
      // NOTE there's a possible bug, deal event before shuffling finish, should confirm
      console.log('before deal final event', JSON.stringify(system))
      const event = system.events.pop()
      const toDealEvent = event.timeEvents[system.time]
      switch (toDealEvent.key) {
        case 'msg':
          eventBus.$emit('notifyMessage', {
            message: toDealEvent.desc
          })
          if (checkWinGame()) {
            eventBus.$emit('notifyMessage', {
              message: '你成功地结束了一切噩梦，游戏胜利🎉',
              confirmBtnText: '重新开始',
              tag: {
                source: 'restart'
              }
            })
          }
          break
        case 'getItem':
          if (checkWinGame()) {
            eventBus.$emit('notifyMessage', {
              message: '你成功地结束了一切噩梦，游戏胜利🎉',
              confirmBtnText: '重新开始',
              tag: {
                source: 'restart'
              }
            })
          }
          break
        case 'battle':
          eventBus.$emit('notifyHappenBattle', {
            count: toDealEvent.zombies,
            disableRunAway: true,
            tag: {
              source: 'finishGame'
            }
          })
          break
        case 'effect':
          player.hp += toDealEvent.addHp
          eventBus.$emit('notifyMessage', {
            message: `${toDealEvent.desc}（生命${toDealEvent.addHp >= 0 ? '+' : ''}${toDealEvent.addHp}}）`
          })
          if (checkWinGame()) {
            eventBus.$emit('notifyMessage', {
              message: '你成功地结束了一切噩梦，游戏胜利🎉',
              confirmBtnText: '重新开始',
              tag: {
                source: 'restart'
              }
            })
          }
          break
      }
    },
    dealItem (isSpecialItem = false) {
      if (!system.events.length) {
        // no more events, should shuffle
        eventBus.$emit('notifyShuffleEvents')
      }
      if (!system.events.length) {
        // when game over, no more events after shuffling
        return
      }
      // NOTE there's a possible bug, deal item before shuffling finish, should confirm
      console.log('before deal item', JSON.stringify(system))
      const event = system.events.pop()
      const toDealItem = JSON.parse(JSON.stringify(ItemConfig.items.find(i => i.key === event.item)))
      if (player.items.length < player.maxItems) {
        player.items.push(toDealItem)
        eventBus.$emit('notifyMessage', {
          message: '获得物品',
          icons: [toDealItem]
        })
        if (!isSpecialItem) {
          this.phase = 'specialEvent'
          this.dealRoomStory()
        } else {
          this.phase = ''
          if (!hasValidEntrance()) {
            this.dealBreakIn()
          }
        }
      } else {
        // no more room for new item
        this.dealDropItem(toDealItem, isSpecialItem)
      }
    },
    dealDropItem (newItem, isSpecialItem = false) {
      eventBus.$emit('notifyMessage', {
        message: '发现新物品！请选择要丢弃的物品',
        icons: [...player.items.map(i => i), newItem],
        selectable: true,
        confirmBtnText: '丢弃',
        tag: {
          source: isSpecialItem ? 'dropSpecialItem' : 'dropEventItem',
          newItem
        }
      })
    },
    dealRunAway (x, y) {
      this.isRunAwayShow = false
      this.runAwayRooms = {}
      player.x += x
      player.y += y
      eventBus.$emit('notifyRedraw')
      eventBus.$emit('notifyMessage', {
        message: '你成功从丧尸攻击中逃脱'
      })
      this.phase = ''
      if (!hasValidEntrance()) {
        this.dealBreakIn()
      }
    },
    dealBreakIn () {
      const breakInIndex = getBreakInEntrance()
      if (breakInIndex > -1) {
        // break in causes a new entrance
        const currentRoomIndex = system.map.findIndex(r => r.x === player.x && r.y === player.y)
        const newRoomData = JSON.parse(JSON.stringify(system.map[currentRoomIndex]))
        newRoomData.doors.push(breakInIndex)
        system.map.splice(currentRoomIndex, 1, newRoomData)
        // console.log(system.map)
        eventBus.$emit('notifyRedraw')
        eventBus.$emit('notifyHappenBattle', {
          count: SystemConfig.breakInCount,
          disableRunAway: true,
          tag: {
            source: 'breakIn'
          }
        })
      } else {
        // NOTE in real world, this situation rarely happens. But to make it robust, I decide it ends with game over
        eventBus.$emit('notifyMessage', {
          message: '你已经无路可逃，游戏结束',
          confirmBtnText: '重新开始',
          tag: {
            source: 'restart'
          }
        })
      }
    },
    dealFetchTotem () {
      player.gotTotem = true
      this.dealEvent(true)
    },
    dealFinishGame () {
      player.buriedTotem = true
      this.dealFinalEvent()
    }
  }
}
</script>

<style scoped lang="less">
.comp-actions {
  position: absolute;
  z-index: 30;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  // background: red;
  .icon-arrow {
    width: 50px;
    height: 50px;
    color: red;
  }
  .layer-rotate {
    position: absolute;
    z-index: 38;
    left: calc((100% - 300px) / 2);
    top: calc((100% - 300px) / 2);
    width: 300px;
    height: 300px;
    .new-room {
      width: 300px;
      height: 300px;
      transition: all 0.3s;
      &.rotate-90 {
        transform: rotate(90deg);
      }
      &.rotate-180 {
        transform: rotate(180deg);
      }
      &.rotate-270 {
        transform: rotate(270deg);
      }
    }
    .icon-rotate {
      position: absolute;
      z-index: 39;
      left: 20px;
      top: 100px;
    }
    .icon-confirm {
      position: absolute;
      z-index: 39;
      right: 20px;
      top: 100px;
    }
  }
  .layer-entrance {
    position: absolute;
    z-index: 31;
    left: calc((100% - 300px) / 2);
    top: calc((100% - 300px) / 2);
    width: 300px;
    height: 300px;
    // background: red;
    &.rotate-90 {
      transform: rotate(90deg);
    }
    &.rotate-180 {
      transform: rotate(180deg);
    }
    &.rotate-270 {
      transform: rotate(270deg);
    }
    .top-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      left: 30%;
      width: 40%;
      top: 0;
      height: 50px;
      // background: red;
    }
    .right-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      top: 30%;
      height: 40%;
      right: 0;
      width: 50px;
      // background: red;
    }
    .bottom-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      left: 30%;
      width: 40%;
      bottom: 0;
      height: 50px;
      // background: red;
    }
    .left-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      top: 30%;
      height: 40%;
      left: 0;
      width: 50px;
      // background: red;
    }
  }
  .layer-runaway {
    position: absolute;
    z-index: 38;
    left: calc((100% - 300px) / 2);
    top: calc((100% - 300px) / 2);
    width: 300px;
    height: 300px;
    // background: red;
    .top-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      left: 30%;
      width: 40%;
      top: 0;
      height: 50px;
      // background: red;
    }
    .right-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      top: 30%;
      height: 40%;
      right: 0;
      width: 50px;
      // background: red;
    }
    .bottom-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      left: 30%;
      width: 40%;
      bottom: 0;
      height: 50px;
      // background: red;
    }
    .left-enter {
      display: flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      z-index: 32;
      top: 30%;
      height: 40%;
      left: 0;
      width: 50px;
      // background: red;
    }
  }
}
</style>
